<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>柱状图</title>
    <script src="https://d3js.org/d3.v3.min.js"></script>
    <style>
        svg {
            font: 10px sans-serif;
        }

        text.title {
            font: 300 78px Helvetica Neue;
            fill: #666;
        }

        .rule line {
            stroke: #fff;
            stroke-opacity: .2;
            shape-rendering: crispEdges;
        }

        .rule:first-child line {
            stroke: #000;
            stroke-opacity: 1;
        }

        rect {
            fill-opacity: .6;
            fill: #e377c2;
        }

        rect:first-child {
            fill: #1f77b4;
        }
    </style>
</head>

<body>
    <div id="chart"></div>
    <script>
        var w = 960,
            h = 500,
            x = d3.scale.linear().range([0, w]),
            y = d3.scale.linear().range([0, h - 40]);

        // An SVG element with a bottom-right origin.
        var svg = d3.select("#chart").append("svg:svg")
            .attr("width", w)
            .attr("height", h)
            .style("padding-right", "30px")
            .append("svg:g")
            .attr("transform", "translate(" + x(1) + "," + (h - 20) + ")scale(-1,-1)");

        // A sliding container to hold the bars.
        var body = svg.append("svg:g")
            .attr("transform", "translate(0,0)");

        // A container to hold the y-axis rules.
        var rules = svg.append("svg:g");

        // A label for the current year.
        var title = svg.append("svg:text")
            .attr("class", "title")
            .attr("dy", ".71em")
            .attr("transform", "translate(" + x(1) + "," + y(1) + ")scale(-1,-1)")
            .text(2000);

        d3.csv("./data/population.csv", function (data) {

            // Convert strings to numbers.
            data.forEach(function (d) {
                d.people = +d.people;
                d.year = +d.year;
                d.age = +d.age;
            });

            // Compute the extent of the data set in age and years.
            var age0 = 0,
                age1 = d3.max(data, function (d) {
                    return d.age;
                }),
                year0 = d3.min(data, function (d) {
                    return d.year;
                }),
                year1 = d3.max(data, function (d) {
                    return d.year;
                }),
                year = year1;

            // Update the scale domains.
            x.domain([0, age1 + 5]);
            y.domain([0, d3.max(data, function (d) {
                return d.people;
            })]);

            // Add rules to show the population values.
            rules = rules.selectAll(".rule")
                .data(y.ticks(10))
                .enter().append("svg:g")
                .attr("class", "rule")
                .attr("transform", function (d) {
                    return "translate(0," + y(d) + ")";
                });

            rules.append("svg:line")
                .attr("x2", w);

            rules.append("svg:text")
                .attr("x", 6)
                .attr("dy", ".35em")
                .attr("transform", "rotate(180)")
                .text(function (d) {
                    return Math.round(d / 1e6) + "M";
                });

            // Add labeled rects for each birthyear.
            var years = body.selectAll("g")
                .data(d3.range(year0 - age1, year1 + 5, 5))
                .enter().append("svg:g")
                .attr("transform", function (d) {
                    return "translate(" + x(year1 - d) + ",0)";
                });

            years.selectAll("rect")
                .data(d3.range(2))
                .enter().append("svg:rect")
                .attr("x", 1)
                .attr("width", x(5) - 2)
                .attr("height", 1e-6);

            years.append("svg:text")
                .attr("y", -6)
                .attr("x", -x(5) / 2)
                .attr("transform", "rotate(180)")
                .attr("text-anchor", "middle")
                .style("fill", "#fff")
                .text(String);

            // Add labels to show the age.
            svg.append("svg:g").selectAll("text")
                .data(d3.range(0, age1 + 5, 5))
                .enter().append("svg:text")
                .attr("text-anchor", "middle")
                .attr("transform", function (d) {
                    return "translate(" + (x(d) + x(5) / 2) + ",-4)scale(-1,-1)";
                })
                .attr("dy", ".71em")
                .text(String);

            // Nest by year then birthyear.
            data = d3.nest()
                .key(function (d) {
                    return d.year;
                })
                .key(function (d) {
                    return d.year - d.age;
                })
                .rollup(function (v) {
                    return v.map(function (d) {
                        return d.people;
                    });
                })
                .map(data);

            // Allow the arrow keys to change the displayed year.
            d3.select(window).on("keydown", function () {
                switch (d3.event.keyCode) {
                    case 37:
                        year = Math.max(year0, year - 10);
                        break;
                    case 39:
                        year = Math.min(year1, year + 10);
                        break;
                }
                redraw();
            });

            redraw();

            function redraw() {
                if (!(year in data)) return;
                title.text(year);

                body.transition()
                    .duration(750)
                    .attr("transform", function (d) {
                        return "translate(" + x(year - year1) + ",0)";
                    });

                years.selectAll("rect")
                    .data(function (d) {
                        return data[year][d] || [0, 0];
                    })
                    .transition()
                    .duration(750)
                    .attr("height", y);
            }
        });
    </script>

</body>

</html>